package com.fuhailiu.opengl.utils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;

public class BitmapUtil {

	private static final String TAG = BitmapUtil.class.getSimpleName();

	public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}
		return roundedSize;
	}

	private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;
		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}
		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}

	public static Bitmap decodeBitmap(InputStream is, int minWidth, int minHeight) {
		if (null == is || minWidth <= 0 || minHeight <= 0) {
			return null;
		}
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(is, null, opts);
		float x = 1.0f * opts.outWidth / minWidth;
		float y = 1.0f * opts.outHeight / minHeight;
		if (x <= 1 || y <= 1)
			opts.inSampleSize = 1;
		else
			opts.inSampleSize = x > y ? (int) y : (int) x;
		opts.inJustDecodeBounds = false;
		Bitmap bmp = BitmapFactory.decodeStream(is, null, opts);
		return bmp;
	}

	public static Bitmap decodeBitmapFromFile(String fileName, int minWidth, int minHeight) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(fileName, opts);
		float x = (float) opts.outWidth / minWidth;
		float y = (float) opts.outHeight / minHeight;
		if (x <= 1 || y <= 1)
			opts.inSampleSize = 1;
		else
			opts.inSampleSize = x > y ? (int) y : (int) x;
		opts.inJustDecodeBounds = false;
		Bitmap bmp = BitmapFactory.decodeFile(fileName, opts);
		return bmp;
	}

	public static void mergeBitmap(Context context, Bitmap dst, Bitmap src, Rect iconRect) {
		BitmapDrawable icon = new BitmapDrawable(context.getResources(), src);
		mergeBitmap(dst, icon, iconRect);
	}

	public static void mergeBitmap(Context context, Bitmap dst, int iconId, Rect iconRect) {
		Drawable icon = context.getResources().getDrawable(iconId);
		mergeBitmap(dst, icon, iconRect);
	}

	public static void mergeBitmap(Bitmap dst, Drawable icon, Rect iconRect) {
		Canvas c = new Canvas(dst);
		icon.setBounds(iconRect);
		icon.draw(c);
	}

	public static Bitmap mergeBitmapWithMask(Bitmap src, Bitmap mask) {
		int bitmapW = src.getWidth();
		int bitmapH = src.getHeight();

		Bitmap dstBmp = src;
		int[] dstbuffer = new int[bitmapW * bitmapH];
		int[] maskbuffer = new int[bitmapW * bitmapH];
		dstBmp.getPixels(dstbuffer, 0, bitmapW, 0, 0, bitmapW, bitmapH);
		mask.getPixels(maskbuffer, 0, bitmapW, 0, 0, bitmapW, bitmapH);
		for (int y = 0; y < bitmapH; y++) {
			for (int x = 0; x < bitmapW; x++) {
				if (maskbuffer[x * bitmapW + y] == 0xff000000)
					dstbuffer[x * bitmapW + y] = 0x00000000;
			}
		}
		dstBmp.setPixels(dstbuffer, 0, bitmapW, 0, 0, bitmapW, bitmapH);
		return dstBmp;
	}

	public static void recycleBitmap(Bitmap bmp) {
		if (null != bmp) {
			if (!bmp.isRecycled()) {
				bmp.recycle();
			}
			bmp = null;
		}
	}

	public static void recycleBitmap(ImageView imageView) {
		if (null == imageView) {
			return;
		}
		Drawable drawable = imageView.getDrawable();
		if (null != drawable && drawable instanceof BitmapDrawable) {
			Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
			if (null != bitmap && !bitmap.isRecycled()) {
				bitmap.recycle();
			}
		}
		imageView.setImageBitmap(null);
	}

	public static Bitmap cropBitmap(Bitmap src, Rect rect) {
		if (src == null || rect == null)
			return null;
		Bitmap bmp = Bitmap.createBitmap(rect.right - rect.left, rect.bottom - rect.top, src.getConfig());
		Canvas canvas = new Canvas(bmp);
		Rect dst = new Rect(0, 0, rect.right - rect.left, rect.bottom - rect.top);
		canvas.drawBitmap(src, rect, dst, null);
		if (src != bmp && !src.isRecycled()) {
			src.recycle();
			src = null;
		}
		return bmp;
	}

	public static Bitmap rotateBitmap(Bitmap src, int degrees) {
		if (src == null || degrees == 0)
			return src;

		int bmpWidth = src.getWidth();
		int bmpHeight = src.getHeight();

		Matrix matrix = new Matrix();
		matrix.setRotate(degrees, bmpWidth / 2.0f, bmpHeight / 2.0f);
		Bitmap bmp = null;
		try {
			bmp = Bitmap.createBitmap(src, 0, 0, bmpWidth, bmpHeight, matrix, true);
			if (src != bmp && !src.isRecycled()) {
				src.recycle();
				src = null;
			}
		} catch (OutOfMemoryError ex) {
			LogUtil.LogE(TAG, "bitmapRotate OutOfMemoryError!");
		}
		return bmp != null ? bmp : src;
	}

	public static Bitmap resizeBitmap(Bitmap src, int dstWidth, int dstHeight) {
		if (src == null) {
			return src;
		}
		Bitmap bmp = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
		if (src != bmp && !src.isRecycled()) {
			src.recycle();
			src = null;
		}
		return bmp;
	}

	public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {

		Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);

		final int color = 0xff424242;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
		final RectF rectF = new RectF(rect);

		paint.setAntiAlias(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(color);
		canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(bitmap, rect, rect, paint);

		if (null != bitmap && bitmap.isRecycled()) {
			bitmap.recycle();
			bitmap = null;
		}
		return output;
	}

	public static boolean saveBitmap2File(String filePath, Bitmap bmp, CompressFormat format) {
		boolean res = true;
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(filePath);
			if (fos != null)
				bmp.compress(format, 100, fos);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			res = false;
		} catch (Exception e) {
			e.printStackTrace();
			res = false;
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		return res;
	}

}
